Channel 发送和接收元素的本质是什么?

All transfer of value on the go channels happens with the copy of value.

就是说 channel 的发送和接收操作本质上都是 “值的拷贝”,无论是从 sender goroutine 的栈到 chan buf,还是从 chan buf 到 receiver goroutine,或者是直接从 sender goroutine 到 receiver goroutine。

举一个例子:

  1. type user struct {
  2. name string
  3. age int8
  4. }
  5. var u = user{name: "Ankur", age: 25}
  6. var g = &u
  7. func modifyUser(pu *user) {
  8. fmt.Println("modifyUser Received Vaule", pu)
  9. pu.name = "Anand"
  10. }
  11. func printUser(u <-chan *user) {
  12. time.Sleep(2 * time.Second)
  13. fmt.Println("printUser goRoutine called", <-u)
  14. }
  15. func main() {
  16. c := make(chan *user, 5)
  17. c <- g
  18. fmt.Println(g)
  19. // modify g
  20. g = &user{name: "Ankur Anand", age: 100}
  21. go printUser(c)
  22. go modifyUser(g)
  23. time.Sleep(5 * time.Second)
  24. fmt.Println(g)
  25. }

运行结果:

  1. &{Ankur 25}
  2. modifyUser Received Vaule &{Ankur Anand 100}
  3. printUser goRoutine called &{Ankur 25}
  4. &{Anand 100}

这里就是一个很好的 share memory by communicating 的例子。

output

一开始构造一个结构体 u,地址是 0x56420,图中地址上方就是它的内容。接着把 &u 赋值给指针 g,g 的地址是 0x565bb0,它的内容就是一个地址,指向 u。

main 程序里,先把 g 发送到 c,根据 copy value 的本质,进入到 chan buf 里的就是 0x56420,它是指针 g 的值(不是它指向的内容),所以打印从 channel 接收到的元素时,它就是 &{Ankur 25}。因此,这里并不是将指针 g “发送” 到了 channel 里,只是拷贝它的值而已。

再强调一次:

Remember all transfer of value on the go channels happens with the copy of value.

参考资料

【深入 channel 底层】https://codeburst.io/diving-deep-into-the-golang-channels-549fd4ed21a8